package http

import (
	"app/internal/web/conf"
	"app/internal/web/controllers"
	"app/internal/web/routers"
	"app/util"
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"
)

type HttpEngine struct {
	cf          *conf.AppConf
	controllers *controllers.ControllerList
	httpconf
	addr string
	srv  http.Server
}

func NewHttpEngine() (http *HttpEngine) {
	http = &HttpEngine{}
	return
}

func NewHttpSrv(cf *conf.AppConf) (srv http.Server) {

	srv = http.Server{
		ReadHeaderTimeout: 10 * time.Second,
		WriteTimeout:      10 * time.Second,
		ReadTimeout:       10 * time.Second,
		MaxHeaderBytes:    1 << 20,
		Addr:              cf.Net.GetNetAddr(),
		Handler:           routers.NewEngine(),
		ErrorLog:          log.New(os.Stderr, "web", log.LstdFlags),
	}
	return
}

func (http *HttpEngine) Init(cf *conf.AppConf) error {

	http.srv = NewHttpSrv(cf)
	http.controllers = controllers.NewControllerList()

	if err := http.LoadConfig(cf.GetConfPath() + cf.API.Conf); err != nil {
		return err
	}

	http.registerController(http.httpconf, http.controllers)

	http.cf = cf

	return nil
}

func (http *HttpEngine) registerController(conf httpconf, controller *controllers.ControllerList) {

	util.Info("web servcie reg controller")
	controller.AllItem(func(value controllers.ControllerInterface) {

		methods := value.GetControllerMethod()
		value.SetRotuers(&http.srv)

		for iloop := 0; iloop < len(methods); iloop++ {

			for i := 0; i < len(conf.Get) && methods[iloop] == controllers.MethodHttpGet; i++ {
				if conf.Get[i].Controllor == value.GetControllerName() && conf.Get[i].Schema == value.GetSchema() {
					routers.RegGetController(&http.srv, value.GetSchema(), value)
				}
			}

			for i := 0; i < len(http.httpconf.Post) && methods[iloop] == controllers.MethodHttpPost; i++ {
				if conf.Post[i].Controllor == value.GetControllerName() && conf.Post[i].Schema == value.GetSchema() {

					routers.RegPostController(&http.srv, value.GetSchema(), value)
				}
			}
		}
	})
}

func (http *HttpEngine) Run() error {
	util.Info("web servcie run")
	return http.srv.ListenAndServe()
}

func (http *HttpEngine) HttpClose() error {
	util.Info("Close listen_addr:%s", http.srv.Addr)
	return http.srv.Close()
}

func (http *HttpEngine) LoadConfig(confpath string) (err error) {

	var fp *os.File
	if fp, err = os.Open(confpath); err != nil {
		return errors.New("http conf file open error")
	}
	var data []byte
	if data, err = ioutil.ReadAll(fp); err != nil {
		return errors.New("http conf file read error")
	}
	if err = fp.Close(); err != nil {
		return errors.New("http conf file close error")
	}
	if err = json.Unmarshal(data, &http.httpconf); err != nil {
		return err
	}
	return nil
}

func (http *HttpEngine) GetConnect() int64 {

	return 1
}
